package com.daoshu.socket.handler.socketio;

import com.alibaba.fastjson.JSON;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import com.daoshu.socket.bean.UserTypeInfo;
import com.daoshu.socket.redis.RedisUtil;
import com.daoshu.socket.service.publisher.PublisherService;
import com.daoshu.socket.view.PushMessageIn;
import com.daoshu.socket.bean.UserInfo;
import com.daoshu.socket.constants.MessageConstants;
import com.daoshu.socket.constants.ReMessageConstants;
import com.daoshu.socket.envent.MessageSaveEvent;
import com.daoshu.socket.envent.MessageStatusEvent;
import com.daoshu.socket.notice.ISyncMessageNotice;
import com.daoshu.socket.service.IUserService;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName: MessageEventHandler
 * @description:
 * @author: Allen
 * @create: 2019-06-24 16:14
 **/
@Component
@Slf4j
public class MessageEventHandler {

    SocketIOServer socketIoServer;

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    IUserService userService;

    @Autowired
    ISyncMessageNotice syncMessageNotice;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    PublisherService publisherService;

    /***
     * 用户Session Map 集合 SessionId-UserInfo
     */
    protected static final Map<String, UserInfo> SESSIOIN_USERS = new ConcurrentHashMap<>();

    @Autowired
    public MessageEventHandler(@Autowired SocketIOServer server) {
        socketIoServer = server;
    }

    /**
     * 客户端连接的时候触发，前端js触发：socket = io.connect("http://192.168.9.209:9092");
     *
     * @param client
     */
    @OnConnect
    public void onConnect(SocketIOClient client) {
        //用户token 唯一标识
        String token = client.getHandshakeData().getSingleUrlParam("token");
        //分组ID
        String groupIds = client.getHandshakeData().getSingleUrlParam("groupIds");
        // 角色
        String role = client.getHandshakeData().getSingleUrlParam("role");
        // id ---> 对应分局，警种和派出所的id
        String id = client.getHandshakeData().getSingleUrlParam("id");
        // 名称 -->对应分局，警种和派出所的名称
        String name = client.getHandshakeData().getSingleUrlParam("name");
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(token);
        if (StringUtils.isNotBlank(groupIds) && groupIds.split(",").length > 0) {
            userInfo.setGroupIds(Lists.newArrayList(groupIds.split(",")));
        }
        userInfo.setClient(client);
        userInfo.setSessionId(client.getSessionId().toString());
        userService.setUserMapInfo(client, userInfo);
        UserTypeInfo userTypeInfo = new UserTypeInfo(token,role,id,name);
        redisUtil.set("kmzdry_websocket_"+token,JSON.toJSON(userTypeInfo));
    }

    /**
     * 客户端关闭连接时触发：前端js触发：socket.disconnect();
     *
     * @param client
     */
    @OnDisconnect
    public void onDisconnect(SocketIOClient client) {
        //用户token 唯一标识
        String token = client.getHandshakeData().getSingleUrlParam("token");
        userService.removeUserMapInfo(client);
        redisUtil.del("kmzdry_websocket_"+token);
        log.info("onDisconnect:" + client.getSessionId() + ",token=" + token);
        //String sendStr = publisherService.sendMessage(token);
        //log.info("token send：" + sendStr);
    }

    /**
     * 自定义消息事件，客户端js触发：socket.emit('message', {body: msg}); 时触发
     * 前端js的 socket.emit("事件名","参数数据")方法，是触发后端自定义消息事件的时候使用的,
     * 前端js的 socket.on("事件名",匿名函数(服务器向客户端发送的数据))为监听服务器端的事件
     *
     * @param client  　客户端信息
     * @param request 请求信息
     * @param in      　客户端发送数据{body: msg}
     */
    @OnEvent(value = MessageConstants.MESSAGE)
    public void onEvent(SocketIOClient client, AckRequest request, PushMessageIn in) {
        log.info("服务器收到消息：" + JSON.toJSONString(in));

        if (in.getTo() == null || in.getTo().isEmpty()) {
            client.sendEvent(ReMessageConstants.RE_EXCEPTION, "需要指定目标用户['1','2'] 或 ['*']");
        }

        if (StringUtils.isBlank(in.getType())) {
            client.sendEvent(ReMessageConstants.RE_EXCEPTION, "需要指定客户端接收消息类型");
        }

        if (in.getBody() == null || in.getBody().isEmpty()) {
            client.sendEvent(ReMessageConstants.RE_EXCEPTION, "消息内容不能为空");
        }
        in.setSocketIOClient(client);
        syncMessageNotice.sendMessageNotice(in);
        // 保存消息事件
        applicationEventPublisher.publishEvent(new MessageSaveEvent(in));
    }


    /***
     * 消息回执接口,PushMessageIn 消息体中带id的需要通过此接口通知是否已送达
     * @param client
     * @param request
     * @param in
     */
    @OnEvent(value = MessageConstants.RECEIPT_MESSAGE)
    public void onReceiptMessage(SocketIOClient client, AckRequest request, PushMessageIn in) {
        applicationEventPublisher.publishEvent(new MessageStatusEvent(in));
    }

}
